import java.util.ArrayList;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.Receiver;

import management.MidiManager.MidiVoices;
import midi.PitchVelocityMidiOutParameter;
import outputAdapters.OutputAdapter;
import outputAdapters.OutputRanges;
import dataModifiers.Modifier;
import inputs.Input;
import inputs.PixelInput;
import processingHandling.WebCamPAppletWrapper;

public class Set_2 extends WebCamPAppletWrapper {

	// Pixel Setup
	PixelInput sampleBankPixelA, sampleBankPixelB, sampleBankPixelC,
			sampleBankPixelD, dronePixel, harmonyPixel, arpPixel;

	// Modifier Setup
	Modifier sampleBankABMod, sampleBankCDMod, sampleBankABCDMod,
			sampleBankABCDHighpassMod, droneMod, harmonyHighpassMod,
			arpHighpassMod;

	// output adapter setup
	OutputAdapter sampleBankAdapter, droneAdapter, harmonyAdapter, arpAdapter;

	// midiout setup
	PitchVelocityMidiOutParameter dronePitVelOut, harmPitVelOut, arpPitVelOut,
			sampBankPitVelOut;

	// midi rec setup
	Receiver midiYoke1Rec; // Midi Receiver used to write to MidiYoke1

	public void Setup() {
		// pixel setup
		sampleBankPixelA = TheInputFactory.createPixelInput(
				this.getWidth() / 8, this.getHeight() / 8, true);
		sampleBankPixelB = TheInputFactory.createPixelInput(
				this.getWidth() / 8, this.getHeight() * 7 / 8, true);
		sampleBankPixelC = TheInputFactory.createPixelInput(
				this.getWidth() * 7 / 8, this.getHeight() / 8, true);
		sampleBankPixelD = TheInputFactory.createPixelInput(
				this.getWidth() * 7 / 8, this.getHeight() * 7 / 8, true);
		dronePixel = TheInputFactory.createPixelInput(this.getWidth() / 2, this
				.getHeight() / 4, true);
		harmonyPixel = TheInputFactory.createPixelInput(this.getWidth() / 2,
				this.getHeight() / 2, true);
		arpPixel = TheInputFactory.createPixelInput(this.getWidth() / 2, this
				.getHeight() * 3 / 4, true);

		// Modifiers!!

		// sample bank AB setup
		ArrayList<Input> sampleBankABAverageInput = new ArrayList<Input>(2);
		sampleBankABAverageInput.add(TheInputFactory.createConstant(sampleBankPixelA.getBlueInput().getValue() - sampleBankPixelA.getRedInput().getValue() - sampleBankPixelA.getGreenInput().getValue(), true));
		sampleBankABAverageInput.add(TheInputFactory.createConstant(sampleBankPixelB.getBlueInput().getValue() - sampleBankPixelA.getRedInput().getValue() - sampleBankPixelA.getGreenInput().getValue(), true));
		sampleBankABMod = TheModifierFactory.createAverage(
				sampleBankABAverageInput, true);
		sampleBankABMod.setRun(false);

		// sample bank CD setup
		ArrayList<Input> sampleBankCDAverageInput = new ArrayList<Input>(2);
		sampleBankCDAverageInput.add(TheInputFactory.createConstant(sampleBankPixelC.getRedInput().getValue() - sampleBankPixelC.getGreenInput().getValue() - sampleBankPixelC.getBlueInput().getValue(), true));
		sampleBankCDAverageInput.add(TheInputFactory.createConstant(sampleBankPixelD.getRedInput().getValue() - sampleBankPixelD.getGreenInput().getValue() - sampleBankPixelD.getBlueInput().getValue(), true));
		sampleBankCDMod = TheModifierFactory.createAverage(
				sampleBankCDAverageInput, true);
		sampleBankCDMod.setRun(false);

		// sample bank ABCD average setup
		ArrayList<Input> sampleBankABCDAverageInput = new ArrayList<Input>(2);
		sampleBankABCDAverageInput.add(sampleBankABMod);
		sampleBankABCDAverageInput.add(sampleBankCDMod);
		sampleBankABCDMod = TheModifierFactory.createAverage(
				sampleBankABCDAverageInput, true);

		// sample bank ABCD highpass setup
		ArrayList<Input> sampleBankABCDHighpassInput = new ArrayList<Input>(2);
		sampleBankABCDHighpassInput.add(TheInputFactory.createConstant(160));
		sampleBankABCDHighpassInput.add(sampleBankABCDMod);
		sampleBankABCDHighpassMod = TheModifierFactory.createAverage(
				sampleBankABCDHighpassInput, true);

		// Drone setup
		ArrayList<Input> droneAverageInput = new ArrayList<Input>(1);
		droneAverageInput.add(dronePixel.getGreenInput());
		droneMod = TheModifierFactory.createAverage(droneAverageInput, true);

		// harmony setup
		ArrayList<Input> harmHighpassInput = new ArrayList<Input>(2);
		harmHighpassInput.add(TheInputFactory.createConstant(160));
		harmHighpassInput.add(harmonyPixel.getBlueInput());
		harmonyHighpassMod = TheModifierFactory.createHighPass(
				harmHighpassInput, true);

		// arp setup
		ArrayList<Input> arpHighpassInput = new ArrayList<Input>(2);
		arpHighpassInput.add(TheInputFactory.createConstant(160));
		arpHighpassInput.add(arpPixel.getRedInput());
		arpHighpassMod = TheModifierFactory.createHighPass(harmHighpassInput,
				true);

		// Output Adapters!

		// scales the highpass mod to 1-8
		sampleBankAdapter = TheOutputAdapterFactory.createScaleAdapter(
				OutputRanges.Samples, sampleBankABCDHighpassMod);
		// drone pitch
		droneAdapter = TheOutputAdapterFactory.createScaleAdapter(
				OutputRanges.Pitch, droneMod);
		// harmony pitch
		harmonyAdapter = TheOutputAdapterFactory.createScaleAdapter(
				OutputRanges.Pitch, harmonyHighpassMod);
		// arp pitch
		arpAdapter = TheOutputAdapterFactory.createScaleAdapter(
				OutputRanges.Pitch, arpHighpassMod);

		// midi setup and binding
		midiYoke1Rec = TheMidiManager.getMidiYoke1Receiver();

		arpPitVelOut = TheMidiOutParameterFactory
				.createPitchVelocityMidiOutParameter(arpAdapter,
						TheInputFactory.createConstant(45), midiYoke1Rec,
						MidiVoices.Arpeggio.ChannelNumber, false);

		harmPitVelOut = TheMidiOutParameterFactory
				.createPitchVelocityMidiOutParameter(harmonyAdapter,
						TheInputFactory.createConstant(70), midiYoke1Rec,
						MidiVoices.Harmony.ChannelNumber, false);

		sampBankPitVelOut = TheMidiOutParameterFactory
				.createPitchVelocityMidiOutParameter(sampleBankAdapter,
						TheInputFactory.createConstant(30), midiYoke1Rec,
						MidiVoices.SampleBank.ChannelNumber, false);

	}

	public void Draw() {
		// Variables to track the previous values of the various instrument
		// pitches
		int prevArp = 0, prevHarm = 0, prevSamp = 0;
		// the pitch difference thresholds
		int arpDiff = 12, harmDiff = 11;

		// if the positive difference in pitch between the previous sample and
		// the current one is larger than the given
		// difference, play the note
		if (abs(prevArp - arpAdapter.getValue()) > arpDiff) {

			prevArp = arpAdapter.getValue();
			arpPitVelOut.Write();
		}

		if (abs(prevHarm - harmonyAdapter.getValue()) > harmDiff) {
			prevHarm = harmonyAdapter.getValue();

			harmPitVelOut.Write();
		}

		if ((prevSamp - sampleBankAdapter.getValue()) != 0) {
			prevSamp = sampleBankAdapter.getValue();
			sampBankPitVelOut.Write();
		}

	}

	public int getFrameRate() {
		return 30;
	}

	public int getHeight() {
		return 480;
	}

	public int getWidth() {
		return 640;
	}
}
